package nl.weeaboo.sh;

import java.awt.event.KeyEvent;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeSet;

import net.java.games.input.Component;
import net.java.games.input.Controller;
import net.java.games.input.ControllerEnvironment;
import net.java.games.input.Component.Identifier;
import net.java.games.input.Component.Identifier.Axis;
import nl.weeaboo.game.input.InputAccumulator;
import nl.weeaboo.game.input.UserInput;
import nl.weeaboo.sh.Config.GamepadConfig;
import timon.common.Log;

public class ControllerMapping {

	private Controller controller;
	private InputAccumulator accum;
	
	private float deadZone = 0.1f;
	private Map<Integer, Integer> mapping;
	private TreeSet<Integer> oldPressed;
	private TreeSet<Integer> newPressed;
	
	public ControllerMapping(GamepadConfig config) {
		controller = getController(config.getId());
		accum = new InputAccumulator(false);
		
		mapping = new HashMap<Integer, Integer>();
		oldPressed = new TreeSet<Integer>();
		newPressed = new TreeSet<Integer>();
		
		if (controller != null) {		
			int analogs = 0;
			int buttons = 0;
			for (int n = 0; n < controller.getComponents().length; n++) {
				Component c = controller.getComponents()[n];
				if (c.getIdentifier() instanceof Axis) {
					Axis ident = (Axis)c.getIdentifier();
	
					if (ident == Axis.X) {
						mapping.put(-n, KeyEvent.VK_LEFT);
						mapping.put( n, KeyEvent.VK_RIGHT);
					} else if (ident == Axis.Y) {
						mapping.put(-n, KeyEvent.VK_UP);
						mapping.put( n, KeyEvent.VK_DOWN);
					}
					analogs++;
				} else if (c.getIdentifier() instanceof Component.Identifier.Button) {
					//Component.Identifier.Button ident = (Component.Identifier.Button)c.getIdentifier();
					
					if (buttons == config.getKey(0)) {
						mapping.put(n, KeyEvent.VK_C);
					} else if (buttons == config.getKey(1)) {
						mapping.put(n, KeyEvent.VK_X);
					} else if (buttons == config.getKey(2)) {
						mapping.put(n, KeyEvent.VK_Z);
					} else if (buttons == config.getKey(3)) {
						mapping.put(n, KeyEvent.VK_ESCAPE);
					}
					buttons++;
				}
			}
		} else {
			Log.warning(String.format("Gamepad not found (id=%d)", config.getId()));
		}
	}
	
	//Functions
	public static Controller getController(int index) {
		int t = 0;
		
		Controller[] controllers = ControllerEnvironment.getDefaultEnvironment().getControllers();
        for (int n = 0; n < controllers.length; n++) {
        	if (controllers[n].getType() == Controller.Type.STICK
        			|| controllers[n].getType() == Controller.Type.GAMEPAD)
        	{
        		if (t == index) {
        			return controllers[n];
        		}
        		t++;
        	}
        }
        return null;
	}
	
	public void update(UserInput input) {
		if (controller == null) return;
		
		Integer i;
		newPressed.clear();
		
		controller.poll();
		for (int n = 0; n < controller.getComponents().length; n++) {
			Component c = controller.getComponents()[n];
			Identifier ident = c.getIdentifier();					
			float p = c.getPollData();
			
			if (ident == Axis.POV) {
				if (p == Component.POV.LEFT || p == Component.POV.UP_LEFT || p == Component.POV.DOWN_LEFT) {
					newPressed.add(KeyEvent.VK_LEFT);
				}
				if (p == Component.POV.RIGHT || p == Component.POV.UP_RIGHT || p == Component.POV.DOWN_RIGHT) {
					newPressed.add(KeyEvent.VK_RIGHT);
				}
				if (p == Component.POV.UP || p == Component.POV.UP_LEFT || p == Component.POV.UP_RIGHT) {
					newPressed.add(KeyEvent.VK_UP);
				}
				if (p == Component.POV.DOWN || p == Component.POV.DOWN_LEFT || p == Component.POV.DOWN_RIGHT) {
					newPressed.add(KeyEvent.VK_DOWN);
				}
			} else {			
				if (Math.abs(p) > deadZone){
					p = (p > 0 ? 1f : -1f);
				}
				
				i = mapping.get(-n);
				if (i != null && p == -1f) newPressed.add(i);
				
				i = mapping.get(n);
				if (i != null && p ==  1f) newPressed.add(i);
			}
		}
		
		//Detect key press changes
		for (int key : oldPressed) {
			if (!newPressed.contains(key)) {
				accum.onKeyReleased(key);
			}
		}
		for (int key : newPressed) {
			if (!oldPressed.contains(key)) {
				accum.onKeyPressed(key);
			}
		}
		
		input.update(accum);

		//Store current state as old state
		TreeSet<Integer> temp = oldPressed;
		oldPressed = newPressed;
		newPressed = temp;
	}
	
	//Getters
	
	//Setters
	
}
